﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Reflection;
using System.Web.Mvc;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel;
using System.Collections;


namespace Wicresoft.SMS.Web
{
    public class DefalutAuthoriseMetadataProvider : IAuthoriseMetadataProvider
    {
        private PropertyInfo _property;
        private object _object;

        public DefalutAuthoriseMetadataProvider(object obj, PropertyInfo property)
        {
            _object = obj;
            _property = property;
        }

        public virtual AuthorisedMetadataModel CreateAuthorisedMetadataModel()
        {
            AuthorisedMetadataModel model = new AuthorisedMetadataModel();

            if (_property == null || _object == null)
                return null;

            //get IAuthorise
            model.SetAuthoriseProvider(GetIAuthoriseImp(),model);

            //get controlType
            model.ControlType = GetControlType();
            
            //get property value which is a AuthoriseFlag
            model.Flag = GetAuthoriseFlag();

            //get username
            model.User = GetUserName();

            //get displayname
            model.Display = GetDisplay();

            //get property name
            model.PropertyName = _property.Name;

            //get property value
            model.PropertyValue = _property.GetValue(_object, null);

            //get property binding
            model.Binding = GetBinding();


            return model;
        }

        /// <summary>
        /// Get the implement of IAuthorise from the _object and _property , _object and _property have been checked
        /// </summary>
        /// <returns></returns>
        protected virtual IAuthorise GetIAuthoriseImp()
        {
            AuthoriseImplementAttribute authoriseImplementAttribute;
            //first check the attribute of _property
            if (_property.IsDefined(typeof(AuthoriseImplementAttribute), false)) //not allow search the inherited class
            {
                authoriseImplementAttribute = _property.GetCustomAttributes(typeof(AuthoriseImplementAttribute), false)[0] as AuthoriseImplementAttribute;
                if (authoriseImplementAttribute != null)
                    return authoriseImplementAttribute.CreateIAuthoriseImplement();
            }
            
            //second check the attribute of _object itself
            Type modelType = _object.GetType();
            modelType.IsDefined(typeof(AuthoriseImplementAttribute), true); //allow search the inherited class
            authoriseImplementAttribute = modelType.GetCustomAttributes(typeof(AuthoriseImplementAttribute), true)[0] as AuthoriseImplementAttribute;
            if (authoriseImplementAttribute != null)
                return authoriseImplementAttribute.CreateIAuthoriseImplement();
            else
                throw new Exception("can't cast to AuthoriseImplementAttribute");
        }

        /// <summary>
        /// Get the input type string from AuthoriseInputTypeAttribute and _property's type , _object and _property have been checked
        /// </summary>
        /// <returns></returns>
        protected virtual ControlType GetControlType()
        {
            if (_property.IsDefined(typeof(AuthoriseControlTypeAttribute), false)) //not allow search the inherited class
            {
                var authoriseControlTypeAttribute = _property.GetCustomAttributes(typeof(AuthoriseControlTypeAttribute), false)[0] as AuthoriseControlTypeAttribute;
                if (authoriseControlTypeAttribute == null)
                    throw new Exception("can't cast to AuthoriseControlTypeAttribute");
                return authoriseControlTypeAttribute.ControlType;
            }

            Type type = _property.PropertyType;
            if (type.Name == "Boolean")
                return ControlType.checkbox;
            if (_property.GetValue(_object,null) != null && _property.GetValue(_object,null) is IEnumerable)
                return ControlType.single_select;
            return ControlType.text;
        }

        /// <summary>
        /// Get the AuthoriseFlag of the _property from _object  , _object and _property have been checked
        /// AuthoriseFlagAttributes and the property itself will be check
        /// </summary>
        /// <returns></returns>
        protected virtual AuthoriseFlag GetAuthoriseFlag()
        {
            AuthoriseFlag _returnValue = AuthoriseFlag.flag_not_define;
            //check AuthoriseFlagAttribute[s]
            if (_property.IsDefined(typeof(AuthoriseFlagAttribute), false)) //not allow search the inherited class
            {
                foreach(object  eachAuthoriseFlag in _property.GetCustomAttributes(typeof(AuthoriseFlagAttribute), false)){
                    _returnValue |= (eachAuthoriseFlag as AuthoriseFlagAttribute).Flags;
                }
            }
            if (_property.PropertyType.Name == "AuthoriseFlag")
                _returnValue |= (AuthoriseFlag)_property.GetValue(_object, null);
            return _returnValue;
        }

        /// <summary>
        /// Get the "UserName" property of the _object  , _object and _property have been checked
        /// "UserName" property will be check
        /// </summary>
        /// <returns></returns>
        protected virtual string GetUserName()
        {
            var _userNameProperty = _object.GetType().GetProperty("UserName");
            if (_userNameProperty == null)
                throw new Exception("custom model not implement the UserName property!");
            if (_userNameProperty.PropertyType.Name != "String")
                throw new Exception("although custom model implements the UserName property , but is not a string!");
            return (string)_userNameProperty.GetValue(_object, null);
        }

        /// <summary>
        /// Get the display from the DisplayNameAttribute and DisplayAttribute
        /// at last _object.ToString() will be returned
        /// </summary>
        /// <returns></returns>
        protected virtual string GetDisplay()
        {
            if (_property.IsDefined(typeof(DisplayNameAttribute), false)) //not allow search the inherited class
            {
                var displayAttribute = _property.GetCustomAttributes(typeof(DisplayNameAttribute), false)[0] as DisplayNameAttribute;
                if (displayAttribute.DisplayName != null)
                    return displayAttribute.DisplayName;
            }

            if (_property.IsDefined(typeof(DisplayAttribute), false)) //not allow search the inherited class
            {
                var displayAttribute = _property.GetCustomAttributes(typeof(DisplayAttribute), false)[0] as DisplayAttribute;
                return displayAttribute.GetName();
            }

            var _propertyValue = _property.GetValue(_object,null);

            if (_propertyValue == null)
                return null;
            return _propertyValue.ToString();
        }

        protected virtual string GetBinding()
        {
            if (_property.IsDefined(typeof(PostbackBindingAttribute), false)) //not allow search the inherited class
            {
                var displayAttribute = _property.GetCustomAttributes(typeof(PostbackBindingAttribute), false)[0] as PostbackBindingAttribute;
                if (displayAttribute.BindingPropertyName != null)
                    return displayAttribute.BindingPropertyName;
            }
            return _property.Name;
        }

    }
}